module de1_avalon_st_audio_if
	(
		// Avalon global signals
		input clk,
		input reset_n,
		
		// Avalon ST - audio fifo
		input [23:0] audio_write_data,
		input audio_valid,
		output audio_ready,

		// Audio I/F
		input clk24M,
		output audio_xck,
		output audio_bclk,
		output audio_daclrck,
		output audio_dacdat
	);

wire [23:0] audio_fifo_q;
wire audio_fifo_rdreq;
wire audio_fifo_rdempty;
wire audio_fifo_wrfull;
wire audio_fifo_wrreq;

wire read_left_channel_data;
wire read_right_channel_data;


reg clk12M;
reg internal_daclrck;
reg [6:0] frame_sync_counter;
reg [23:0] audio_dac_shift_reg;
reg [23:0] left_channel_data;
reg [23:0] right_channel_data;
reg right_channel_next_flag;
reg left_channel_data_ready;
reg right_channel_data_ready;
reg internal_audio_ready;

always @(posedge clk24M or negedge reset_n)
begin
	// create the 12M output clock for convenience
	if(!reset_n)
		begin
			clk12M <= 1'b0;
		end
	else
		begin
			clk12M <= ~clk12M;
		end		
	
	// create the frame sync counter which counts 125 states from 0 thru 124
	if(!reset_n)
		begin
			frame_sync_counter <= 0;
		end
	else if(clk12M)
		begin
			frame_sync_counter <= (frame_sync_counter == 124) ? (0) : (frame_sync_counter + 1);
		end

	// create the internal version of daclrck
	if(!reset_n)
		begin
			internal_daclrck <= 0;
		end
	else if((frame_sync_counter == 1) & clk12M)
		begin
			internal_daclrck <= 1;
		end
	else if((frame_sync_counter == 2) & clk12M)
		begin
			internal_daclrck <= 0;
		end

	// create the dac data shift register
	if(!reset_n)
		begin
			audio_dac_shift_reg <= 0;
		end
	else if((frame_sync_counter == 1) & clk12M)
		begin
			audio_dac_shift_reg <= left_channel_data;
		end
	else if((frame_sync_counter == 25) & clk12M)
		begin
			audio_dac_shift_reg <= right_channel_data;
		end
	else
		begin
			audio_dac_shift_reg <= (clk12M) ? ({audio_dac_shift_reg[22:0], 1'b0}) : (audio_dac_shift_reg);
		end
		
	// create the left and right channel demux registers
	if(!reset_n)
		begin
			left_channel_data <= 24'h000000;
			right_channel_data <= 24'h000000;
			right_channel_next_flag <= 1'b0;
			left_channel_data_ready <= 1'b0;
			right_channel_data_ready <= 1'b0;
		end
	else if(left_channel_data_ready & clk12M)
		begin
			left_channel_data <= audio_fifo_q;
			right_channel_next_flag <= 1'b1;
			left_channel_data_ready <= 1'b0;
		end
	else if(right_channel_data_ready & clk12M)
		begin
			right_channel_data <= audio_fifo_q;
			right_channel_next_flag <= 1'b0;
			right_channel_data_ready <= 1'b0;
		end
	else if(read_left_channel_data & !clk12M)
		begin
			left_channel_data_ready <= 1'b1;
		end
	else if(read_right_channel_data & !clk12M)
		begin
			right_channel_data_ready <= 1'b1;
		end
end

always @(posedge clk or negedge reset_n)
begin
	// create the frame sync counter which counts 125 states from 0 thru 124
	if(!reset_n)
		begin
			internal_audio_ready <= 0;
		end
	else
		begin
			internal_audio_ready = !audio_fifo_wrfull & !internal_audio_ready & !audio_valid;
		end

end

assign audio_xck = clk12M;
assign audio_bclk = clk12M;
assign audio_dacdat = audio_dac_shift_reg[23];
assign audio_daclrck = internal_daclrck;

assign audio_ready = internal_audio_ready;

assign audio_fifo_wrreq = audio_valid;
assign audio_fifo_rdreq = (read_left_channel_data | read_right_channel_data) & !clk12M;

assign read_left_channel_data = (frame_sync_counter == 0) & !audio_fifo_rdempty & !right_channel_next_flag;
assign read_right_channel_data = (frame_sync_counter == 24) & !audio_fifo_rdempty & right_channel_next_flag;

de1_audio_fifo	audio_fifo (
	.data ( audio_write_data ),
	.rdclk ( clk24M ),
	.rdreq ( audio_fifo_rdreq ),
	.wrclk ( clk ),
	.wrreq ( audio_fifo_wrreq ),
	.q ( audio_fifo_q ),
	.rdempty ( audio_fifo_rdempty ),
	.wrfull ( audio_fifo_wrfull )
	);

endmodule
